package com.jiangli.service.Search.Impl;


import com.jiangli.entity.Dish;
import com.jiangli.entity.Merchant;
import com.jiangli.mapper.DishMapper;
import com.jiangli.mapper.SearchHotMapper;
import com.jiangli.result.PageResult;
import com.jiangli.service.MerchantService;
import com.jiangli.service.Search.DishCandidateService;
import com.jiangli.service.Search.DishIndexService;
import com.jiangli.service.Search.DishSearchService;
import com.jiangli.service.impl.DishServiceImpl;
import com.jiangli.service.impl.MerchantServiceImpl;
import com.jiangli.utils.Sreach.EditDistanceUtils;
import com.jiangli.utils.Sreach.SearchUtils;
import com.jiangli.vo.DishBriefVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 菜品搜索服务（带编辑距离容错和Redis缓存）
 */
@Service
@Slf4j
public class DishSearchServiceImpl implements DishSearchService {

    // Redis缓存前缀
    private static final String SEARCH_RESULT_PREFIX = "search:result:";
    // 缓存过期时间（60分钟）
    private static final long CACHE_EXPIRE_MINUTES = 60;

    @Autowired
    private DishIndexService indexService;

    @Autowired
    private DishCandidateService candidateService;

    @Autowired
    private DishMapper dishMapper;

    @Autowired
    private SearchHotMapper searchHotMapper;

    @Autowired
    private DishServiceImpl dishServiceImpl;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private MerchantServiceImpl merchantService;

    /**
     * 带容错和缓存的搜索主方法
     */
    public PageResult search(String keyword, int page, int size) {
        if (keyword == null || keyword.trim().isEmpty()) {
            PageResult pageResult = new PageResult();
            pageResult.setTotal(0);
            pageResult.setRecords(Collections.emptyList());
            return pageResult;
        }
        keyword = keyword.trim();
        log.info("search keyword: " + keyword);
        // 记录搜索热词
        searchHotMapper.incrementCount(keyword);

        // 生成缓存键
        String cacheKey = generateCacheKey(keyword);

        // 尝试从缓存获取ID列表
        List<Long> allIds = getIdsFromCache(cacheKey);

        // 缓存未命中，执行搜索逻辑
        if (CollectionUtils.isEmpty(allIds)) {
            // 1. 精确搜索
            allIds = preciseSearchForIds(keyword);

            // 2. 精确搜索无结果，启动编辑距离容错
            if (CollectionUtils.isEmpty(allIds)) {
                log.info("精确搜索无结果，尝试容错搜索");
                List<String> candidates = candidateService.getAllCandidates();
                String bestMatch = findBestMatch(keyword, candidates);
                log.info("相似词: {}", bestMatch);

                // 3. 用相似词重新搜索
                if (bestMatch != null) {
                    allIds = preciseSearchForIds(bestMatch);
                }
            }

            // 将搜索结果ID存入缓存
            if (!CollectionUtils.isEmpty(allIds)) {
                saveIdsToCache(cacheKey, allIds);
            } else {
                log.info("未找到与关键词[{}]匹配的菜品", keyword);
                PageResult pageResult = new PageResult();
                pageResult.setTotal(0);
                pageResult.setRecords(Collections.emptyList());
                return pageResult;
            }
        } else {
            log.info("从缓存获取搜索结果，关键词: {}", keyword);
        }

        // 执行分页并查询菜品详情
        PageResult pageResult = new PageResult();
        pageResult.setTotal(allIds.size());
        pageResult.setRecords(getDishesByPage(allIds, page, size));
        return pageResult;
    }

    /**
     * 生成缓存键
     */
    private String generateCacheKey(String keyword) {
        return SEARCH_RESULT_PREFIX + keyword;
    }

    /**
     * 从缓存获取ID列表
     */
    private List<Long> getIdsFromCache(String cacheKey) {
        try {
            List<String> idStrs = stringRedisTemplate.opsForList().range(cacheKey, 0, -1);
            if (!CollectionUtils.isEmpty(idStrs)) {
                return idStrs.stream()
                        .map(Long::valueOf)
                        .collect(Collectors.toList());
            }
        } catch (Exception e) {
            log.error("从Redis获取搜索结果ID失败", e);
        }
        return null;
    }

    /**
     * 将ID列表存入缓存
     */
    private void saveIdsToCache(String cacheKey, List<Long> ids) {
        try {
            // 先删除可能存在的旧缓存
            stringRedisTemplate.delete(cacheKey);

            // 转换为字符串并存入Redis
            List<String> idStrs = ids.stream()
                    .map(String::valueOf)
                    .collect(Collectors.toList());

            stringRedisTemplate.opsForList().rightPushAll(cacheKey, idStrs);
            // 设置过期时间
            stringRedisTemplate.expire(cacheKey, CACHE_EXPIRE_MINUTES, TimeUnit.MINUTES);
            log.info("搜索结果ID已存入缓存，key: {}, 数量: {}", cacheKey, ids.size());
        } catch (Exception e) {
            log.error("将搜索结果ID存入Redis失败", e);
        }
    }

    /**
     * 精确搜索，只返回ID列表
     */
    private List<Long> preciseSearchForIds(String keyword) {
        // 分词处理
        List<String> keywords = SearchUtils.ikSegment(keyword);
        log.info("search 精确分词keyword: " + keywords.toString());
        if (CollectionUtils.isEmpty(keywords)) {
            return Collections.emptyList();
        }

        // 查询每个关键词对应的菜品ID
        List<Set<String>> idStrSets = keywords.stream()
                .map(indexService::getDishIdsByKeyword)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        log.info("idStrSets: " + idStrSets.toString());
        if (CollectionUtils.isEmpty(idStrSets)) {
            log.info("精确搜索无结果");
            return Collections.emptyList();
        }

        // 计算ID交集（同时匹配所有关键词）
        Set<String> idStrs = SearchUtils.intersect(idStrSets);
        if (CollectionUtils.isEmpty(idStrs)) {
            log.info("交集精确搜索无结果");
            return Collections.emptyList();
        }

        // 转换为Long类型ID
        List<Long> ids = idStrs.stream()
                .map(Long::valueOf)
                .collect(Collectors.toList());
        log.info("匹配到的菜品ID数量: " + ids.size());

        // 查询所有菜品信息用于过滤和排序
        List<Dish> dishes = dishServiceImpl.getDishesFromCacheOrDB(ids);

        // 过滤城市和排序后返回ID列表
        return filterAndSort(dishes,keywords).stream()
                .map(Dish::getId)
                .collect(Collectors.toList());
    }

    /**
     * 根据分页参数从ID列表中获取对应页的菜品
     */
    private List<DishBriefVO> getDishesByPage(List<Long> allIds, int page, int size) {
        // 计算分页范围
        int start = (page - 1) * size;
        if (start < 0) start = 0;
        int end = Math.min(start + size, allIds.size());

        // 如果没有数据，返回空列表
        if (start >= end) {
            return Collections.emptyList();
        }

        // 获取当前页的ID列表
        List<Long> pageIds = allIds.subList(start, end);
        List<Dish> dishList = dishServiceImpl.getDishesFromCacheOrDB(pageIds);
        List<DishBriefVO> dishList2 = new ArrayList<>();
        for (Dish value : dishList) {
            DishBriefVO dishVO = new DishBriefVO();
            List<Long> merchantIds = new ArrayList<Long>();
            merchantIds.add((Long.valueOf(value.getMerchantId())));
            List<Merchant> merchant = merchantService.getCurrentMerchant(merchantIds);
            log.info("商家应该有一个{}", merchant.size());
            merchant.add(new Merchant());
            BeanUtils.copyProperties(value, dishVO);
            log.info("商家{}", merchant.get(0));
            dishVO.setMerchant(merchant.get(0).getMerchantName());
            dishVO.setLocation(merchant.get(0).getLocation());
            dishList2.add(dishVO);
        }
        // 查询菜品详情
        return dishList2;
    }

    /**
     * 用编辑距离查找最相似的候选词
     */
    private String findBestMatch(String input, List<String> candidates) {
        if (CollectionUtils.isEmpty(candidates)) {
            return null;
        }

        String bestMatch = null;
        double maxSimilarity = 0.0;
        int inputLen = input.length();

        for (String candidate : candidates) {
            // 过滤长度差异过大的候选词
            int candidateLen = candidate.length();

            // 计算相似度
            log.info("候选词："+candidate);
            double similarity = EditDistanceUtils.calculateSimilarity(input, candidate);
            log.info("相似度: " + similarity);

            if (similarity > maxSimilarity) {
                maxSimilarity = similarity;
                bestMatch = candidate;
                log.info("相似词{}",candidate);
            }
        }

        return bestMatch;
    }

    /**
     * 过滤城市并排序
     */
    private List<Dish> filterAndSort(List<Dish> dishes, List<String> keywords) {

        // 按销量和评分排序
        return dishes.stream()
                .sorted((d1, d2) -> {
                    // 优先比较销量（降序）
                    if (!d1.getRatingCount().equals(d2.getRatingCount())) {
                        return d2.getRatingCount().compareTo(d1.getRatingCount());
                    }
                    // 再比较评分（降序）
                    return d2.getPrice().compareTo(d1.getPrice());
                })
                .collect(Collectors.toList());
    }
}
